package consumer.handler;

import com.google.protobuf.ByteString;
import common.parse.StringParser;
import common.proto.JSONUtil;
import common.proto.RPCProtoParamOuterClass;
import common.proto.RPCProtoReqOuterClass;
import common.proto.RPCProtoRespOuterClass;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.concurrent.DefaultEventExecutor;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Promise;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @ClassName RpcHandler
 * @Description
 * @Author Jingxiao.Ye
 * @Date 2022/1/2 下午11:43
 * @Version V1.0
 * @Since JDK 11
 */
public class RpcHandler extends SimpleChannelInboundHandler<FullHttpResponse> {

    public static final DefaultEventExecutor eventExecutor = new DefaultEventExecutor(Executors.newCachedThreadPool());

    private Promise<Object> resultPromise;

    private String host;
    private int port;
    private String className;
    private String methodName;
    private Class[] paramClasses;
    private Object[] params;

    public RpcHandler(String host,int port,String className,String methodName,Class[] paramClasses,Object[] params,Promise<Object> resultPromise) {
        super();
        this.host = host;
        this.port = port;
        this.className = className;
        this.methodName = methodName;
        this.paramClasses = paramClasses;
        this.params = params;
        this.resultPromise = resultPromise;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpResponse fullHttpResponse) throws Exception {
        ByteBuf content = fullHttpResponse.content();
        byte[] bytes = ByteBufUtil.getBytes(content);
        //解析pro
        RPCProtoRespOuterClass.RPCProtoResp rpcProtoResp = RPCProtoRespOuterClass.RPCProtoResp.parseFrom(bytes);
        ByteString result = rpcProtoResp.getResult();
        Object resultObj = null;
        if(result != null){
            String parse = StringParser.parse(result.toByteArray());
            resultObj = JSONUtil.objectMapper.readValue(parse, Object.class);
        }
        resultPromise.setSuccess(resultObj);
        channelHandlerContext.close();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        RPCProtoReqOuterClass.RPCProtoReq.Builder builder = RPCProtoReqOuterClass.RPCProtoReq.newBuilder()
                .setClassName(className)
                .setMethodName(methodName);
        if(paramClasses !=null && params != null){
            List<ByteString> list = new ArrayList<>();
            for (int i = 0; i < paramClasses.length; i++) {
                Class paramClass = paramClasses[i];
                Object param = params[i];
                String s = JSONUtil.objectMapper.writeValueAsString(param);
                RPCProtoParamOuterClass.RPCProtoParam rpcProtoParam = RPCProtoParamOuterClass.RPCProtoParam.newBuilder()
                        .setClassName(paramClass.getName()).setContent(ByteString.copyFrom(s.getBytes())).build();
                list.add(rpcProtoParam.toByteString());
            }
            builder.setParams(ByteString.copyFrom(list));
        }
        RPCProtoReqOuterClass.RPCProtoReq rpcProtoReq = builder.build();
        byte[] bytes = rpcProtoReq.toByteArray();
        DefaultFullHttpRequest defaultFullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.POST, "http://" + host + ":" + port + "/", Unpooled.wrappedBuffer(bytes));
        defaultFullHttpRequest.headers().add("Content-Type", "application/octet-stream").add("Content-Length",bytes.length);
        ctx.writeAndFlush(defaultFullHttpRequest);
    }
}
